package ch.ethz.fcl.metrobuzz.render.techniques.arrow;

import javax.vecmath.Vector2d;

import org.lwjgl.opengl.GL11;

import ch.ethz.fcl.metrobuzz.MBContainer;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Point2D;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Polygon;
import ch.ethz.fcl.metrobuzz.tools.MBGL;
import ch.ethz.fcl.metrobuzz.tools.MBTools;

public class Arrow {
	private static float lwRatio = 1.5f; // length / width
	private static float tailWidthRatio = 0.4f; // tail width to width ratio
	private static float headLWRatio = 0.7f; // head length to width ratio

	public static Polygon generateArrow(Point2D head, Point2D tail, float width) {
		float dist = head.distance(tail);
		Vector2d dir = tail.getDir(head);
		lwRatio = dist / width;

		Polygon polygon = generateDefaultArrow(head, dir, width);

		lwRatio = 1.5f;
		return polygon;
	}

	// default arrow width
	public static Polygon generateDefaultArrow(Point2D head, Vector2d dir,
			float width) {
		Vector2d verDir1 = MBTools.rotate(dir, Math.PI / 2);

		Vector2d inverseDir = MBTools.rotate(dir, Math.PI);

		float headLength = headLWRatio * width;
		float tailWidth = tailWidthRatio * width;
		float tailLength = (lwRatio - headLWRatio) * width;

		Point2D headEndLeft = head.getPointAt(verDir1, width / 2).getPointAt(
				inverseDir, headLength);
		Point2D headEndRight = head.getPointAt(verDir1, -width / 2).getPointAt(
				inverseDir, headLength);

		Point2D tailFrontLeft = head.getPointAt(verDir1, tailWidth / 2)
				.getPointAt(inverseDir, headLength);
		Point2D tailFrontRight = head.getPointAt(verDir1, -tailWidth / 2)
				.getPointAt(inverseDir, headLength);

		Point2D tailEndLeft = tailFrontLeft.getPointAt(inverseDir, tailLength);
		Point2D tailEndRight = tailFrontRight
				.getPointAt(inverseDir, tailLength);

		Polygon polygon = new Polygon();
		polygon.addPoint(head);
		polygon.addPoint(headEndLeft);
		polygon.addPoint(tailFrontLeft);
		polygon.addPoint(tailEndLeft);
		polygon.addPoint(tailEndRight);
		polygon.addPoint(tailFrontRight);
		polygon.addPoint(headEndRight);

		return polygon;

	}

	public static void render(MBContainer container, Point2D head, Point2D tail) {
		Vector2d dir = tail.getDir(head);

		Vector2d verDir1 = MBTools.rotate(dir, Math.PI / 2);
		Vector2d inverseDir = MBTools.rotate(dir, Math.PI);

		float width = container.getViewer().getProjection().getWorldDistance(6);

		Point2D pb = head.getPointAt(inverseDir, width * 2);
		Point2D p1 = pb.getPointAt(verDir1, width);
		Point2D p2 = pb.getPointAt(verDir1, -width);
		
		GL11.glLineWidth(1.0f);
		GL11.glBegin(GL11.GL_LINES);
		MBGL.render(p1);
		MBGL.render(head);

		MBGL.render(p2);
		MBGL.render(head);

		MBGL.render(tail);
		MBGL.render(head);
		GL11.glEnd();

	}

	public static void render(Polygon arrow) {
		if (arrow == null || arrow.getPoints().size() != 7)
			return;

		GL11.glLineWidth(1.0f);

		// render as lines
		GL11.glBegin(GL11.GL_LINE_STRIP);
		MBGL.render(arrow.getPoints().get(0));
		MBGL.render(arrow.getPoints().get(1));
		MBGL.render(arrow.getPoints().get(2));
		MBGL.render(arrow.getPoints().get(3));
		MBGL.render(arrow.getPoints().get(4));
		MBGL.render(arrow.getPoints().get(5));
		MBGL.render(arrow.getPoints().get(6));
		MBGL.render(arrow.getPoints().get(0));
		GL11.glEnd();

		// fill the shape
		GL11.glBegin(GL11.GL_POLYGON);
		MBGL.render(arrow.getPoints().get(0));
		MBGL.render(arrow.getPoints().get(1));
		MBGL.render(arrow.getPoints().get(6));
		GL11.glEnd();

		// fill the shape
		GL11.glBegin(GL11.GL_POLYGON);
		MBGL.render(arrow.getPoints().get(2));
		MBGL.render(arrow.getPoints().get(3));
		MBGL.render(arrow.getPoints().get(4));
		MBGL.render(arrow.getPoints().get(5));
		GL11.glEnd();
	}
}
